Skip to content

Commit

Permalink
introduce treefmt.withConfig
Browse files Browse the repository at this point in the history
This is useful if you want to configure treefmt with nix, and precisely
pass all the commands from nixpkgs.

Co-authored-by: Sridhar Ratnakumar <[email protected]>
  • Loading branch information
zimbatm and Sridhar Ratnakumar committed Sep 21, 2022
1 parent f2bbb89 commit 8467716
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 2 deletions.
26 changes: 25 additions & 1 deletion default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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 { };
Expand Down
15 changes: 14 additions & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 113 additions & 0 deletions module-options.nix
Original file line number Diff line number Diff line change
@@ -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"
'';
};
};

0 comments on commit 8467716

Please sign in to comment.