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 19, 2022
1 parent ef8f965 commit c0a0c12
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 2 deletions.
1 change: 1 addition & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
use nix
122 changes: 121 additions & 1 deletion default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,120 @@ let

cargoToml = with builtins; (fromTOML (readFile ./Cargo.toml));

# 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 || lib.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 { };

module = { config, ... }: {
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.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"
'';
};
};

# Use the Nix module system to validate the treefmt config file format.
evalModule = config:
lib.evalModules {
modules = [ module config ];
};

# What is used when invoking `nix run github:numtide/treefmt`
treefmt = rustPackages.rustPlatform.buildRustPackage {
inherit (cargoToml.package) name version;
Expand All @@ -34,6 +148,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 +188,7 @@ let
});
in
{
inherit treefmt devShell;
inherit treefmt devShell evalModule module;

# 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";
};
};
};
}

0 comments on commit c0a0c12

Please sign in to comment.