treefmt: refactor `withConfig` and `buildConfig` to use `evalConfig` (#406685)

Introduces a new modules-based implementation that is used by both
`withConfig` and `buildConfig`.

Previously we used a module eval for `settings`. This PR makes it so
that all args passed to `withConfig` are now module options. `settings`
is now a submodule of the wider `evalConfig` configuration.

As well as being a better overall design (IMO), using a module eval
enables adding additional options in the future. E.g. we could add
`programs` options similar to those maintained by treefmt-nix.

authored by Matt Sturgeon and committed by GitHub 0858f1bc 6f5afe34

+219 -91
+1 -1
pkgs/by-name/ni/nixfmt-tree/package.nix
··· 21 treefmtWithConfig = treefmt.withConfig { 22 name = "nixfmt-tree"; 23 24 - settings = [ 25 # Default settings 26 { 27 _file = ./package.nix;
··· 21 treefmtWithConfig = treefmt.withConfig { 22 name = "nixfmt-tree"; 23 24 + settings = lib.mkMerge [ 25 # Default settings 26 { 27 _file = ./package.nix;
-30
pkgs/by-name/tr/treefmt/build-config.nix
··· 1 - { 2 - lib, 3 - formats, 4 - }: 5 - module: 6 - let 7 - settingsFormat = formats.toml { }; 8 - configuration = lib.evalModules { 9 - modules = [ 10 - { 11 - _file = ./build-config.nix; 12 - freeformType = settingsFormat.type; 13 - } 14 - { 15 - # Wrap user's modules with a default file location 16 - _file = "<treefmt.buildConfig args>"; 17 - imports = lib.toList module; 18 - } 19 - ]; 20 - }; 21 - settingsFile = settingsFormat.generate "treefmt.toml" configuration.config; 22 - in 23 - settingsFile.overrideAttrs { 24 - passthru = { 25 - format = settingsFormat; 26 - settings = configuration.config; 27 - inherit (configuration) _module options; 28 - optionType = configuration.type; 29 - }; 30 - }
···
+98
pkgs/by-name/tr/treefmt/lib.nix
···
··· 1 + { 2 + lib, 3 + pkgs, 4 + treefmt, 5 + }: 6 + { 7 + /** 8 + Evaluate a treefmt configuration. 9 + 10 + # Type 11 + 12 + ``` 13 + Module -> Configuration 14 + ``` 15 + 16 + # Inputs 17 + 18 + `module` 19 + : A treefmt module, configuring options that include: 20 + - `name`: `String` (default `"treefmt-with-config"`) 21 + - `settings`: `Module` (default `{ }`) 22 + - `runtimeInputs`: `[Derivation]` (default `[ ]`) 23 + */ 24 + evalConfig = 25 + module: 26 + lib.evalModules { 27 + class = "treefmtConfig"; 28 + specialArgs.modulesPath = ./modules; 29 + modules = [ 30 + { 31 + _file = "treefmt.evalConfig"; 32 + _module.args.pkgs = lib.mkOptionDefault pkgs; 33 + package = lib.mkOptionDefault treefmt; 34 + } 35 + { 36 + _file = "<treefmt.evalConfig args>"; 37 + imports = lib.toList module; 38 + } 39 + ./modules/default.nix 40 + ]; 41 + }; 42 + 43 + /** 44 + Wrap treefmt, configured using structured settings. 45 + 46 + # Type 47 + 48 + ``` 49 + Module -> Derivation 50 + ``` 51 + 52 + # Inputs 53 + 54 + `module` 55 + : A treefmt module, configuring options that include: 56 + - `name`: `String` (default `"treefmt-with-config"`) 57 + - `settings`: `Module` (default `{ }`) 58 + - `runtimeInputs`: `[Derivation]` (default `[ ]`) 59 + */ 60 + withConfig = 61 + module: 62 + let 63 + configuration = treefmt.evalConfig { 64 + _file = "<treefmt.withConfig args>"; 65 + imports = lib.toList module; 66 + }; 67 + in 68 + configuration.config.result; 69 + 70 + /** 71 + Build a treefmt config file from structured settings. 72 + 73 + # Type 74 + 75 + ``` 76 + Module -> Derivation 77 + ``` 78 + 79 + # Inputs 80 + 81 + `settings` 82 + : A settings module, used to build a treefmt config file 83 + */ 84 + buildConfig = 85 + module: 86 + let 87 + configuration = treefmt.evalConfig { 88 + _file = "<treefmt.buildConfig args>"; 89 + settings.imports = lib.toList module; 90 + }; 91 + in 92 + configuration.config.configFile.overrideAttrs { 93 + passthru = { 94 + inherit (configuration.config) settings; 95 + options = (opt: opt.type.getSubOptions opt.loc) configuration.options.settings; 96 + }; 97 + }; 98 + }
+9
pkgs/by-name/tr/treefmt/modules/default.nix
···
··· 1 + { 2 + _class = "treefmtConfig"; 3 + 4 + imports = [ 5 + ./options.nix 6 + ./settings.nix 7 + ./wrapper.nix 8 + ]; 9 + }
+40
pkgs/by-name/tr/treefmt/modules/options.nix
···
··· 1 + { lib, config, ... }: 2 + { 3 + options = { 4 + name = lib.mkOption { 5 + type = lib.types.str; 6 + default = lib.getName config.package + "-with-config"; 7 + defaultText = lib.literalExpression "\"\${getName package}-with-config\""; 8 + description = '' 9 + Name to use for the wrapped treefmt package. 10 + ''; 11 + }; 12 + 13 + runtimeInputs = lib.mkOption { 14 + type = with lib.types; listOf package; 15 + default = [ ]; 16 + description = '' 17 + Packages to include on treefmt's PATH. 18 + ''; 19 + }; 20 + 21 + configFile = lib.mkOption { 22 + type = lib.types.path; 23 + # Ensure file is copied to the store 24 + apply = file: if lib.isDerivation file then file else "${file}"; 25 + defaultText = lib.literalMD "generated from [](#opt-treefmt-settings)"; 26 + description = '' 27 + The treefmt config file. 28 + ''; 29 + }; 30 + 31 + package = lib.mkOption { 32 + type = lib.types.package; 33 + defaultText = lib.literalExpression "pkgs.treefmt"; 34 + description = '' 35 + The treefmt package to wrap. 36 + ''; 37 + internal = true; 38 + }; 39 + }; 40 + }
+26
pkgs/by-name/tr/treefmt/modules/settings.nix
···
··· 1 + { 2 + lib, 3 + pkgs, 4 + config, 5 + modulesPath, 6 + ... 7 + }: 8 + let 9 + settingsFormat = pkgs.formats.toml { }; 10 + in 11 + { 12 + options.settings = lib.mkOption { 13 + type = lib.types.submoduleWith { 14 + specialArgs = { inherit modulesPath; }; 15 + modules = [ 16 + { freeformType = settingsFormat.type; } 17 + ]; 18 + }; 19 + default = { }; 20 + description = '' 21 + Settings used to build a treefmt config file. 22 + ''; 23 + }; 24 + 25 + config.configFile = lib.mkOptionDefault (settingsFormat.generate "treefmt.toml" config.settings); 26 + }
+40
pkgs/by-name/tr/treefmt/modules/wrapper.nix
···
··· 1 + { 2 + lib, 3 + pkgs, 4 + config, 5 + options, 6 + ... 7 + }: 8 + { 9 + options.result = lib.mkOption { 10 + type = lib.types.package; 11 + description = '' 12 + The wrapped treefmt package. 13 + ''; 14 + readOnly = true; 15 + internal = true; 16 + }; 17 + 18 + config.result = 19 + pkgs.runCommand config.name 20 + { 21 + nativeBuildInputs = [ pkgs.makeBinaryWrapper ]; 22 + env = { 23 + inherit (config) configFile; 24 + binPath = lib.makeBinPath config.runtimeInputs; 25 + }; 26 + passthru = { 27 + inherit (config) runtimeInputs; 28 + inherit config options; 29 + }; 30 + inherit (config.package) meta version; 31 + } 32 + '' 33 + mkdir -p $out/bin 34 + makeWrapper \ 35 + ${lib.getExe config.package} \ 36 + $out/bin/treefmt \ 37 + --prefix PATH : "$binPath" \ 38 + --add-flags "--config-file $configFile" 39 + ''; 40 + }
+5 -28
pkgs/by-name/tr/treefmt/package.nix
··· 1 { 2 lib, 3 buildGoModule, 4 - callPackage, 5 callPackages, 6 fetchFromGitHub, 7 }: ··· 30 ]; 31 32 passthru = { 33 - /** 34 - Wrap treefmt, configured using structured settings. 35 - 36 - # Type 37 - 38 - ``` 39 - AttrSet -> Derivation 40 - ``` 41 - 42 - # Inputs 43 - 44 - - `name`: `String` (default `"treefmt-configured"`) 45 - - `settings`: `Module` (default `{ }`) 46 - - `runtimeInputs`: `[Derivation]` (default `[ ]`) 47 - */ 48 - withConfig = callPackage ./with-config.nix { }; 49 - 50 - /** 51 - Build a treefmt config file from structured settings. 52 - 53 - # Type 54 - 55 - ``` 56 - Module -> Derivation 57 - ``` 58 - */ 59 - buildConfig = callPackage ./build-config.nix { }; 60 61 tests = callPackages ./tests.nix { }; 62 };
··· 1 { 2 lib, 3 buildGoModule, 4 callPackages, 5 fetchFromGitHub, 6 }: ··· 29 ]; 30 31 passthru = { 32 + inherit (callPackages ./lib.nix { }) 33 + evalConfig 34 + withConfig 35 + buildConfig 36 + ; 37 38 tests = callPackages ./tests.nix { }; 39 };
-32
pkgs/by-name/tr/treefmt/with-config.nix
··· 1 - { 2 - lib, 3 - runCommand, 4 - treefmt, 5 - makeBinaryWrapper, 6 - }: 7 - { 8 - name ? "treefmt-with-config", 9 - settings ? { }, 10 - runtimeInputs ? [ ], 11 - }: 12 - runCommand name 13 - { 14 - nativeBuildInputs = [ makeBinaryWrapper ]; 15 - treefmtExe = lib.getExe treefmt; 16 - binPath = lib.makeBinPath runtimeInputs; 17 - passthru = { inherit runtimeInputs; }; 18 - configFile = treefmt.buildConfig { 19 - # Wrap user's modules with a default file location 20 - _file = "<treefmt.withConfig settings arg>"; 21 - imports = lib.toList settings; 22 - }; 23 - inherit (treefmt) meta version; 24 - } 25 - '' 26 - mkdir -p $out/bin 27 - makeWrapper \ 28 - $treefmtExe \ 29 - $out/bin/treefmt \ 30 - --prefix PATH : "$binPath" \ 31 - --add-flags "--config-file $configFile" 32 - ''
···