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

feat(options): granular style formatting (#85)

* implement granular style formatting

* attempt to fix CI

* document new styling options

---------

Co-authored-by: Victor Borja <vborja@apache.org>

authored by

musjj
Victor Borja
and committed by
GitHub
1f95f96b f98aee32

+219 -61
+5 -7
dev/flake.nix
··· 1 1 # DO-NOT-EDIT. This file was auto-generated using github:vic/flake-file. 2 2 # Use `nix run .#write-flake` to regenerate it. 3 3 { 4 - 5 4 outputs = inputs: inputs.flake-parts.lib.mkFlake { inherit inputs; } (inputs.import-tree ./modules); 6 5 7 6 inputs = { 8 7 devshell = { 9 - inputs.nixpkgs.follows = "nixpkgs"; 10 8 url = "github:numtide/devshell"; 9 + inputs.nixpkgs.follows = "nixpkgs"; 11 10 }; 12 11 flake-file.url = "path:.."; 13 12 flake-parts = { 14 - inputs.nixpkgs-lib.follows = "nixpkgs-lib"; 15 13 url = "github:hercules-ci/flake-parts"; 14 + inputs.nixpkgs-lib.follows = "nixpkgs-lib"; 16 15 }; 17 16 import-tree.url = "github:vic/import-tree"; 18 17 nix-auto-follow = { 19 - inputs.nixpkgs.follows = "nixpkgs"; 20 18 url = "github:fzakaria/nix-auto-follow"; 19 + inputs.nixpkgs.follows = "nixpkgs"; 21 20 }; 22 21 nix-unit = { 22 + url = "github:nix-community/nix-unit"; 23 23 inputs = { 24 24 flake-parts.follows = "flake-parts"; 25 25 nixpkgs.follows = "nixpkgs"; 26 26 treefmt-nix.follows = "treefmt-nix"; 27 27 }; 28 - url = "github:nix-community/nix-unit"; 29 28 }; 30 29 nixpkgs.url = "https://channels.nixos.org/nixpkgs-unstable/nixexprs.tar.xz"; 31 30 nixpkgs-lib.follows = "nixpkgs"; 32 31 treefmt-nix = { 33 - inputs.nixpkgs.follows = "nixpkgs"; 34 32 url = "github:numtide/treefmt-nix"; 33 + inputs.nixpkgs.follows = "nixpkgs"; 35 34 }; 36 35 }; 37 - 38 36 }
+81 -15
dev/modules/_lib/default.nix
··· 93 93 value = value; 94 94 }; 95 95 96 + priorityComparator = 97 + priority: a: b: 98 + let 99 + findPriority = name: lib.lists.findFirstIndex (p: p == name) (lib.length priority) priority; 100 + priorityA = findPriority a; 101 + priorityB = findPriority b; 102 + in 103 + if priorityA == priorityB then a < b else priorityA < priorityB; 104 + 105 + priorityMapAttrsToList = 106 + f: priority: attrs: 107 + lib.pipe attrs [ 108 + lib.attrsToList 109 + (lib.sort (a: b: priorityComparator priority a.name b.name)) 110 + (map ({ name, value }: f name value)) 111 + ]; 112 + 113 + styleHead = 114 + styles: 115 + if styles == [ ] then 116 + { 117 + attrSortPriority = [ ]; 118 + attrSep = " "; 119 + } 120 + else 121 + lib.pipe styles [ 122 + lib.head 123 + ( 124 + { 125 + attrSortPriority ? [ ], 126 + attrSep ? " ", 127 + }: 128 + { 129 + inherit attrSortPriority attrSep; 130 + } 131 + ) 132 + ]; 133 + 134 + styleTail = styles: if styles == [ ] then [ ] else lib.tail styles; 135 + 96 136 # expr to code 97 137 nixCode = 98 - x: 99 - if lib.isStringLike x then 100 - lib.strings.escapeNixString x 101 - else if lib.isAttrs x then 102 - lib.pipe x [ 103 - (lib.mapAttrsToList nixAttr) 104 - (map ({ name, value }: "${name} = ${nixCode value}; ")) 105 - (values: "{ ${lib.concatStringsSep " " values} }") 138 + { 139 + expr, 140 + styles ? [ ], 141 + }: 142 + let 143 + style = styleHead styles; 144 + in 145 + if lib.isStringLike expr then 146 + lib.strings.escapeNixString expr 147 + else if lib.isAttrs expr then 148 + lib.pipe expr [ 149 + (priorityMapAttrsToList nixAttr style.attrSortPriority) 150 + (map ( 151 + { name, value }: 152 + "${name} = ${ 153 + nixCode { 154 + expr = value; 155 + styles = styleTail styles; 156 + } 157 + };" 158 + )) 159 + (values: "{ ${lib.concatStringsSep style.attrSep values} }") 106 160 ] 107 - else if lib.isList x then 108 - lib.pipe x [ 109 - (lib.map nixCode) 161 + else if lib.isList expr then 162 + lib.pipe expr [ 163 + (lib.map ( 164 + expr: 165 + nixCode { 166 + inherit expr; 167 + styles = styleTail styles; 168 + } 169 + )) 110 170 (values: "[ ${lib.concatStringsSep " " values} ]") 111 171 ] 112 - else if x == true then 172 + else if expr == true then 113 173 "true" 114 - else if x == false then 174 + else if expr == false then 115 175 "false" 116 176 else 117 - toString x; 177 + toString expr; 118 178 119 179 in 120 180 { 121 - inherit inputsExpr isNonEmptyString nixCode; 181 + inherit 182 + inputsExpr 183 + isNonEmptyString 184 + priorityComparator 185 + priorityMapAttrsToList 186 + nixCode 187 + ; 122 188 }
+14
docs/src/content/docs/reference/options.mdx
··· 54 54 }; 55 55 ``` 56 56 57 + ## Style options 58 + 59 + | Option | Type | Description | 60 + |---|---|---| 61 + | `flake-file.style.sep.flake` | `str` | The separator used between the top-level attributes of the flake | 62 + | `flake-file.style.sep.inputs` | `str` | The separator used between the top-level attributes of inputs | 63 + | `flake-file.style.sep.inputSchema` | `str` | The separator used between the top-level attributes of an input schema | 64 + | `flake-file.style.sep.nixConfig` | `str` | The separator used between the top-level attributes of nixConfig | 65 + | `flake-file.style.sortPriority.flake` | `listOf str` | When alphabetically sorting the top-level attributes of the flake, names within this list will receive a higher sort order according to its index | 66 + | `flake-file.style.sortPriority.inputs` | `listOf str` | When alphabetically sorting the top-level attributes of inputs, names within this list will receive a higher sort order according to its index | 67 + | `flake-file.style.sortPriority.inputSchema` | `listOf str` | When alphabetically sorting the top-level attributes of an input schema, names within this list will receive a higher sort order according to its index | 68 + | `flake-file.style.sortPriority.nixConfig` | `listOf str` | When alphabetically sorting the top-level attributes of nixConfig, names within this list will receive a higher sort order according to its index | 69 + 70 + 57 71 ## Hook Options 58 72 59 73 | Option | Type | Description |
+1
modules/options/default.nix
··· 8 8 ./prune-lock.nix 9 9 ./write-hooks.nix 10 10 ./check-hooks.nix 11 + ./style.nix 11 12 ]; 12 13 }
+61
modules/options/style.nix
··· 1 + { lib, ... }: 2 + let 3 + mkSepOption = 4 + name: default: 5 + lib.mkOption { 6 + description = '' 7 + The separator used between the top-level attributes of ${name}. 8 + ''; 9 + type = lib.types.str; 10 + inherit default; 11 + }; 12 + 13 + mkSortPriorityOption = 14 + name: default: 15 + lib.mkOption { 16 + description = '' 17 + When alphabetically sorting the top-level attributes of ${name}, names within 18 + this list will receive a higher sort order according to its index. 19 + ''; 20 + type = lib.types.listOf lib.types.str; 21 + inherit default; 22 + }; 23 + in 24 + { 25 + options.flake-file.style = { 26 + sep = { 27 + flake = mkSepOption "the flake" "\n\n"; 28 + inputs = mkSepOption "inputs" "\n"; 29 + inputSchema = mkSepOption "an input schema" "\n"; 30 + nixConfig = mkSepOption "nixConfig" "\n"; 31 + }; 32 + 33 + sortPriority = { 34 + flake = mkSortPriorityOption "the flake" [ 35 + "description" 36 + "outputs" 37 + "nixConfig" 38 + "inputs" 39 + ]; 40 + inputs = mkSortPriorityOption "inputs" [ ]; 41 + inputSchema = mkSortPriorityOption "an input schema" [ 42 + "type" 43 + "host" 44 + "url" 45 + "owner" 46 + "repo" 47 + "path" 48 + "id" 49 + "dir" 50 + "narHash" 51 + "rev" 52 + "ref" 53 + "submodules" 54 + "flake" 55 + "follows" 56 + "inputs" 57 + ]; 58 + nixConfig = mkSortPriorityOption "nixConfig" [ ]; 59 + }; 60 + }; 61 + }
+55 -31
modules/write-flake.nix
··· 5 5 ... 6 6 }@top: 7 7 let 8 - inherit (import ./../dev/modules/_lib lib) inputsExpr isNonEmptyString nixCode; 8 + inherit (import ./../dev/modules/_lib lib) 9 + inputsExpr 10 + isNonEmptyString 11 + priorityMapAttrsToList 12 + nixCode 13 + ; 14 + 15 + inherit (config.flake-file.style) sep sortPriority; 9 16 10 17 flake-file = config.flake-file; 11 18 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 - ]; 19 + unformatted = 20 + let 21 + filteredAttrs = lib.filterAttrs (_: v: v != null) { 22 + inherit description outputs nixConfig; 23 + inputs = flakeInputs; 24 + }; 25 + exprs = priorityMapAttrsToList (_: v: v) sortPriority.flake filteredAttrs; 26 + in 27 + addHeader '' 28 + { 29 + ${lib.concatStringsSep sep.flake exprs} 30 + } 31 + ''; 28 32 29 33 description = 30 34 if isNonEmptyString flake-file.description then 31 - '' 32 - description = ${nixCode flake-file.description}; 33 - '' 35 + "description = ${nixCode { expr = flake-file.description; }};" 34 36 else 35 - ""; 37 + null; 36 38 37 - outputs = '' 38 - outputs = ${flake-file.outputs}; 39 - ''; 39 + outputs = "outputs = ${flake-file.outputs};"; 40 40 41 41 nixConfig = 42 42 let ··· 47 47 ) flake-file.nixConfig; 48 48 in 49 49 if filteredConfig != { } then 50 - '' 51 - nixConfig = ${nixCode filteredConfig}; 52 - '' 50 + "nixConfig = ${ 51 + nixCode { 52 + expr = filteredConfig; 53 + styles = [ 54 + { 55 + attrSortPriority = sortPriority.nixConfig; 56 + attrSep = sep.nixConfig; 57 + } 58 + ]; 59 + } 60 + };" 53 61 else 54 - ""; 62 + null; 55 63 56 - flakeInputs = '' 57 - inputs = ${nixCode (inputsExpr flake-file.inputs)}; 58 - ''; 64 + flakeInputs = "inputs = ${ 65 + nixCode { 66 + expr = inputsExpr flake-file.inputs; 67 + styles = [ 68 + { 69 + attrSortPriority = sortPriority.inputs; 70 + attrSep = sep.inputs; 71 + } 72 + { 73 + attrSortPriority = sortPriority.inputSchema; 74 + attrSep = sep.inputSchema; 75 + } 76 + { 77 + attrSortPriority = sortPriority.inputs; 78 + attrSep = sep.inputs; 79 + } 80 + ]; 81 + } 82 + };"; 59 83 60 84 addHeader = 61 85 code: if isNonEmptyString flake-file.do-not-edit then flake-file.do-not-edit + code else code;
+1 -1
modules/write-inputs.nix
··· 8 8 # DO-NOT-EDIT: Generated by github:vic/flake-file. 9 9 # To re-generate use: nix-shell . -A flake-file.sh --run write-inputs 10 10 '' 11 - + (nixCode (inputsExpr flake-file.inputs)); 11 + + (nixCode { expr = inputsExpr flake-file.inputs; }); 12 12 13 13 inputsFile = 14 14 pkgs:
-2
templates/default/flake.nix
··· 1 1 # DO-NOT-EDIT. This file was auto-generated using github:vic/flake-file. 2 2 # Use `nix run .#write-flake` to regenerate it. 3 3 { 4 - 5 4 outputs = inputs: import ./outputs.nix inputs; 6 5 7 6 inputs = { ··· 9 8 flake-parts.url = "github:hercules-ci/flake-parts"; 10 9 nixpkgs.url = "https://channels.nixos.org/nixpkgs-unstable/nixexprs.tar.xz"; 11 10 }; 12 - 13 11 }
+1 -3
templates/dendritic/flake.nix
··· 1 1 # DO-NOT-EDIT. This file was auto-generated using github:vic/flake-file. 2 2 # Use `nix run .#write-flake` to regenerate it. 3 3 { 4 - 5 4 outputs = inputs: inputs.flake-parts.lib.mkFlake { inherit inputs; } (inputs.import-tree ./modules); 6 5 7 6 inputs = { 8 7 flake-file.url = "github:vic/flake-file"; 9 8 flake-parts = { 10 - inputs.nixpkgs-lib.follows = "nixpkgs-lib"; 11 9 url = "github:hercules-ci/flake-parts"; 10 + inputs.nixpkgs-lib.follows = "nixpkgs-lib"; 12 11 }; 13 12 import-tree.url = "github:vic/import-tree"; 14 13 nixpkgs.url = "https://channels.nixos.org/nixpkgs-unstable/nixexprs.tar.xz"; 15 14 nixpkgs-lib.follows = "nixpkgs"; 16 15 }; 17 - 18 16 }
-2
templates/parts/flake.nix
··· 1 1 # DO-NOT-EDIT. This file was auto-generated using github:vic/flake-file. 2 2 # Use `nix run .#write-flake` to regenerate it. 3 3 { 4 - 5 4 outputs = inputs: import ./outputs.nix inputs; 6 5 7 6 nixConfig = { ··· 15 14 nixpkgs.url = "https://channels.nixos.org/nixpkgs-unstable/nixexprs.tar.xz"; 16 15 treefmt-nix.url = "github:numtide/treefmt-nix"; 17 16 }; 18 - 19 17 }