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.
This commit is contained in:
Matt Sturgeon
2025-05-19 17:22:32 +02:00
committed by GitHub
parent 6f5afe3482
commit 0858f1bc43
9 changed files with 219 additions and 91 deletions
+1 -1
View File
@@ -21,7 +21,7 @@ let
treefmtWithConfig = treefmt.withConfig {
name = "nixfmt-tree";
settings = [
settings = lib.mkMerge [
# Default settings
{
_file = ./package.nix;
-30
View File
@@ -1,30 +0,0 @@
{
lib,
formats,
}:
module:
let
settingsFormat = formats.toml { };
configuration = lib.evalModules {
modules = [
{
_file = ./build-config.nix;
freeformType = settingsFormat.type;
}
{
# Wrap user's modules with a default file location
_file = "<treefmt.buildConfig args>";
imports = lib.toList module;
}
];
};
settingsFile = settingsFormat.generate "treefmt.toml" configuration.config;
in
settingsFile.overrideAttrs {
passthru = {
format = settingsFormat;
settings = configuration.config;
inherit (configuration) _module options;
optionType = configuration.type;
};
}
+98
View File
@@ -0,0 +1,98 @@
{
lib,
pkgs,
treefmt,
}:
{
/**
Evaluate a treefmt configuration.
# Type
```
Module -> Configuration
```
# Inputs
`module`
: A treefmt module, configuring options that include:
- `name`: `String` (default `"treefmt-with-config"`)
- `settings`: `Module` (default `{ }`)
- `runtimeInputs`: `[Derivation]` (default `[ ]`)
*/
evalConfig =
module:
lib.evalModules {
class = "treefmtConfig";
specialArgs.modulesPath = ./modules;
modules = [
{
_file = "treefmt.evalConfig";
_module.args.pkgs = lib.mkOptionDefault pkgs;
package = lib.mkOptionDefault treefmt;
}
{
_file = "<treefmt.evalConfig args>";
imports = lib.toList module;
}
./modules/default.nix
];
};
/**
Wrap treefmt, configured using structured settings.
# Type
```
Module -> Derivation
```
# Inputs
`module`
: A treefmt module, configuring options that include:
- `name`: `String` (default `"treefmt-with-config"`)
- `settings`: `Module` (default `{ }`)
- `runtimeInputs`: `[Derivation]` (default `[ ]`)
*/
withConfig =
module:
let
configuration = treefmt.evalConfig {
_file = "<treefmt.withConfig args>";
imports = lib.toList module;
};
in
configuration.config.result;
/**
Build a treefmt config file from structured settings.
# Type
```
Module -> Derivation
```
# Inputs
`settings`
: A settings module, used to build a treefmt config file
*/
buildConfig =
module:
let
configuration = treefmt.evalConfig {
_file = "<treefmt.buildConfig args>";
settings.imports = lib.toList module;
};
in
configuration.config.configFile.overrideAttrs {
passthru = {
inherit (configuration.config) settings;
options = (opt: opt.type.getSubOptions opt.loc) configuration.options.settings;
};
};
}
@@ -0,0 +1,9 @@
{
_class = "treefmtConfig";
imports = [
./options.nix
./settings.nix
./wrapper.nix
];
}
@@ -0,0 +1,40 @@
{ lib, config, ... }:
{
options = {
name = lib.mkOption {
type = lib.types.str;
default = lib.getName config.package + "-with-config";
defaultText = lib.literalExpression "\"\${getName package}-with-config\"";
description = ''
Name to use for the wrapped treefmt package.
'';
};
runtimeInputs = lib.mkOption {
type = with lib.types; listOf package;
default = [ ];
description = ''
Packages to include on treefmt's PATH.
'';
};
configFile = lib.mkOption {
type = lib.types.path;
# Ensure file is copied to the store
apply = file: if lib.isDerivation file then file else "${file}";
defaultText = lib.literalMD "generated from [](#opt-treefmt-settings)";
description = ''
The treefmt config file.
'';
};
package = lib.mkOption {
type = lib.types.package;
defaultText = lib.literalExpression "pkgs.treefmt";
description = ''
The treefmt package to wrap.
'';
internal = true;
};
};
}
@@ -0,0 +1,26 @@
{
lib,
pkgs,
config,
modulesPath,
...
}:
let
settingsFormat = pkgs.formats.toml { };
in
{
options.settings = lib.mkOption {
type = lib.types.submoduleWith {
specialArgs = { inherit modulesPath; };
modules = [
{ freeformType = settingsFormat.type; }
];
};
default = { };
description = ''
Settings used to build a treefmt config file.
'';
};
config.configFile = lib.mkOptionDefault (settingsFormat.generate "treefmt.toml" config.settings);
}
@@ -0,0 +1,40 @@
{
lib,
pkgs,
config,
options,
...
}:
{
options.result = lib.mkOption {
type = lib.types.package;
description = ''
The wrapped treefmt package.
'';
readOnly = true;
internal = true;
};
config.result =
pkgs.runCommand config.name
{
nativeBuildInputs = [ pkgs.makeBinaryWrapper ];
env = {
inherit (config) configFile;
binPath = lib.makeBinPath config.runtimeInputs;
};
passthru = {
inherit (config) runtimeInputs;
inherit config options;
};
inherit (config.package) meta version;
}
''
mkdir -p $out/bin
makeWrapper \
${lib.getExe config.package} \
$out/bin/treefmt \
--prefix PATH : "$binPath" \
--add-flags "--config-file $configFile"
'';
}
+5 -28
View File
@@ -1,7 +1,6 @@
{
lib,
buildGoModule,
callPackage,
callPackages,
fetchFromGitHub,
}:
@@ -30,33 +29,11 @@ buildGoModule rec {
];
passthru = {
/**
Wrap treefmt, configured using structured settings.
# Type
```
AttrSet -> Derivation
```
# Inputs
- `name`: `String` (default `"treefmt-configured"`)
- `settings`: `Module` (default `{ }`)
- `runtimeInputs`: `[Derivation]` (default `[ ]`)
*/
withConfig = callPackage ./with-config.nix { };
/**
Build a treefmt config file from structured settings.
# Type
```
Module -> Derivation
```
*/
buildConfig = callPackage ./build-config.nix { };
inherit (callPackages ./lib.nix { })
evalConfig
withConfig
buildConfig
;
tests = callPackages ./tests.nix { };
};
-32
View File
@@ -1,32 +0,0 @@
{
lib,
runCommand,
treefmt,
makeBinaryWrapper,
}:
{
name ? "treefmt-with-config",
settings ? { },
runtimeInputs ? [ ],
}:
runCommand name
{
nativeBuildInputs = [ makeBinaryWrapper ];
treefmtExe = lib.getExe treefmt;
binPath = lib.makeBinPath runtimeInputs;
passthru = { inherit runtimeInputs; };
configFile = treefmt.buildConfig {
# Wrap user's modules with a default file location
_file = "<treefmt.withConfig settings arg>";
imports = lib.toList settings;
};
inherit (treefmt) meta version;
}
''
mkdir -p $out/bin
makeWrapper \
$treefmtExe \
$out/bin/treefmt \
--prefix PATH : "$binPath" \
--add-flags "--config-file $configFile"
''