introduce treefmt.withConfig

This is useful if you want to configure treefmt with nix, and precisely
pass all the commands from nixpkgs.

Co-authored-by: Sridhar Ratnakumar <srid@srid.ca>
This commit is contained in:
zimbatm 2022-05-20 16:02:45 +02:00
parent f2bbb89e39
commit 84677166df
No known key found for this signature in database
GPG Key ID: 71BAF6D40C1D63D7
3 changed files with 152 additions and 2 deletions

View File

@ -13,6 +13,18 @@ let
cargoToml = with builtins; (fromTOML (readFile ./Cargo.toml));
# Use the Nix module system to validate the treefmt config file format.
evalModule = config:
lib.evalModules {
modules = [
{
_module.args = { inherit nixpkgs lib treefmt; };
}
./module-options.nix
config
];
};
# What is used when invoking `nix run github:numtide/treefmt`
treefmt = rustPackages.rustPlatform.buildRustPackage {
inherit (cargoToml.package) name version;
@ -34,6 +46,12 @@ let
cargoLock.lockFile = ./Cargo.lock;
meta.description = "one CLI to format the code tree";
passthru.withConfig = config:
let
mod = evalModule config;
in
mod.config.build.wrapper;
};
# Add all the dependencies of treefmt, plus more build tools
@ -68,7 +86,13 @@ let
});
in
{
inherit treefmt devShell;
inherit treefmt devShell evalModule;
# module that generates and wraps the treefmt config with Nix
module = ./module-options.nix;
# reduce a bit of repetition
inherit (treefmt.passthru) withConfig;
# A collection of packages for the project
docs = nixpkgs.callPackage ./docs { };

View File

@ -18,9 +18,22 @@
};
in
{
inherit packages;
# This contains a mix of packages, modules, ...
legacyPackages = packages;
devShells.default = packages.devShell;
# In Nix 2.8 you can run `nix fmt` to format this whole repo.
#
# Because we load the treefmt.toml and don't define links to the
# packages in Nix, the formatter has to run inside of `nix develop`
# to have the various tools on the PATH.
#
# It also assumes that the project root has a flake.nix (override this by setting `projectRootFile`).
formatter = packages.treefmt.withConfig {
settings = nixpkgs.lib.importTOML ./treefmt.toml;
projectRootFile = "flake.nix";
};
};
};
}

113
module-options.nix Normal file
View File

@ -0,0 +1,113 @@
{ lib, nixpkgs, treefmt, ... }:
let
# A new kind of option type that calls lib.getExe on derivations
exeType = lib.mkOptionType {
name = "exe";
description = "Path to executable";
check = (x: lib.isString x || builtins.isPath x || lib.isDerivation x);
merge = loc: defs:
let res = lib.mergeOneOption loc defs; in
if lib.isString res || builtins.isPath res then
"${res}"
else
lib.getExe res;
};
# The schema of the treefmt.toml data structure.
configSchema = with lib; {
excludes = mkOption {
description = "A global list of paths to exclude. Supports glob.";
type = types.listOf types.str;
default = [ ];
example = [ "./node_modules/**" ];
};
formatter = mkOption {
type = types.attrsOf (types.submodule [{
options = {
command = mkOption {
description = "Executable obeying the treefmt formatter spec";
type = exeType;
};
options = mkOption {
description = "List of arguments to pass to the command";
type = types.listOf types.str;
default = [ ];
};
includes = mkOption {
description = "List of files to include for formatting. Supports globbing.";
type = types.listOf types.str;
};
excludes = mkOption {
description = "List of files to exclude for formatting. Supports globbing. Takes precedence over the includes.";
type = types.listOf types.str;
default = [ ];
};
};
}]);
default = { };
description = "Set of formatters to use";
};
};
configFormat = nixpkgs.formats.toml { };
in
{
# Schema
options = {
settings = configSchema;
package = lib.mkOption {
description = "Package wrapped in the build.wrapper output";
type = lib.types.package;
default = treefmt;
};
projectRootFile = lib.mkOption {
description = ''
File to look for to determine the root of the project in the
build.wrapper.
'';
example = "flake.nix";
};
# Outputs
build = {
configFile = lib.mkOption {
description = ''
Contains the generated config file derived from the settings.
'';
type = lib.types.path;
};
wrapper = lib.mkOption {
description = ''
The treefmt package, wrapped with the config file.
'';
type = lib.types.package;
};
};
};
# Config
config.build = {
configFile = configFormat.generate "treefmt.toml" config.settings;
wrapper = nixpkgs.writeShellScriptBin "treefmt" ''
find_up() (
ancestors=()
while [[ ! -f "$1" ]]; do
ancestors+=("$PWD")
if [[ $PWD == / ]]; then
echo "ERROR: Unable to locate the projectRootFile ($1) in any of: ''${ancestors[*]@Q}" >&2
exit 1
fi
cd ..
done
)
tree_root=$(find_up "${config.projectRootFile}")
exec ${config.package}/bin/treefmt --config-file ${config.build.configFile} "$@" --tree-root "$tree_root"
'';
};
};