Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add treefmt.withConfig #169

Merged
merged 3 commits into from
Sep 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env bash
# Environment variables for the project. See https://direnv.net/
if nix flake metadata &>/dev/null; then
use flake
else
use nix
fi
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
12 changes: 6 additions & 6 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

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