Properly configure `typos` in `pre-commit-hooks.nix` (now `git-hooks.nix`)
2024-04: Ongoing Upstream Discussion
There is an ongoing upstream discussion for a pull request of mine that tries to mitigate this issues of the typos integration with pre-commit-hooks.nix I present in the following. I don’t know if it is ever getting merged – many opinions, limited time, stressed maintainers, complicated edge cases, different valid variants of usage of typos, stressed me – not blaming anyone!. However, IMHO, you should configure typos as follows, and you are good to go:
Terminology & Background
typosis the new shining star in the sky of source code spell checkers.- pre-commit-hooks.nix is a seamless integration of https://pre-commit.com git hooks with Nix. (It was recently renamed to
git-hooks.nixupstream.) pre-commitis the binary used to combine all linters, formatters, and other checkers in a single command using a.pre-commit-config.yml. This is the tool invoked by the git hooks, however, it is a standalone component.
pre-commit doesn’t need to be used with git hooks at all. In fact, pre-commit can be used as single entry into all checks without ever being used as a git hook. So, $ pre-commit run --all-files just run all checks on the repository. I use it that way and that’s perfectly valid and productive.
My Expectation
IMHO, $ pre-commit run typos [--all-files] must behave exactly like $ typos without any doubt or exception. typos is the base, pre-commit the additional convenience. Not the other way around!
Problems
pre-commitis meant to pass all files that should be checked to the tools as argument, such as$ some-checker-tool src/foo.c src/bar.c include/bar.h(this information comes from.pre-commit-config.yaml)typosis supposed to be invoked on the tree, i.e.,$ typos- Using a
.typos.tomlfile one can exclude certain files or directories. - This is the setup I’ve seen in dozens of projects.
- But yes, you can also invoke
typoslike this:$ typos src/foo.c src/bar.c include/bar.h, but this feels wrong.
- Using a
typoshas a massive memory and CPU usage when thousands of files are passed to it as argument, even when the typos-flag--force-excludedis usedpre-commit-hooks.nixis structured in a way that it can’t use the excludes of the.typos.tomlfile (my PR is trying to fix that)- Just setting
pass_filenames = falseas default got negative feedback upstream typosexclude rules uses globs whereas pre-commit uses regex. This makes the implementation harder.- I have a project where over 70.000 files in a folder are excluded in
.typos.toml. However,pre-commit-hooks.nixcreates a.pre-commit-config.yamlfile that instructspre-committo pass ALL OF THEM totyposwhich let my computer explode - Again, I do not use the git hooks but
pre-commitas centralized binary to run all checks. With the current default upstream definitions howpre-commitshould invoketypos, I can’t runpre-commit run [typos] --all-fileswithout additional configuration.
But again. It is entirely unacceptable and counter-intuitive that $ pre-commit typos --all-files behaves differently from running just $ typos with a proper .typos.toml.
Conclusion, Outlook, and Solutions
There is no one to blame for the stuck upstream discussion, just an unfortunate situation and people that use typos in different ways. I don’t think it is worth it spending more time in this time sink upstream. (Locally applicable) solutions to this problem are:
- The
typosutility should be fixed to not explode your PC when it receives that many arguments (I never investigated this, and I do not have the capacity to, unfortunately) - Setting
hooks.typos.pass_filenames = falseis perfectly fine IMHO. Just lettyposfigure out the excludes by itself by reading its configuration file. - Otherwise, you can set
hooks.typos.excludes = (builtins.fromTOML (builtins.readFile ../.typos.toml).files or { }).extend-exclude or [ ]);as long as your excludes do not use globs (*).
So the following code snippet shows my solution (broken down to what’s relevant). For simplicity, the code snipped uses a Nix channel to fetch nixpkgs:
let
pkgs = import <nixpkgs> { };
# Commit ID from 2024-01-08
pre-commit-hooks = import (builtins.fetchTarball "https://github.com/cachix/pre-commit-hooks.nix/tarball/ea07fa07f222a5c4baacbcdbf529276ef0ddc6ca");
in
# Configured with the module options defined in `modules/pre-commit.nix`:
pre-commit-hooks.run {
src = ./.;
# Set the pkgs to get the tools for the hooks from.
tools = pkgs;
hooks = {
typos = {
enable = true;
pass_filenames = false;
# As this is a string and not a Nix Path upstream, the excludes can
# never be evaluated by pre-commit-hooks.nix.
settings.configPath = ".typos.toml";
};
};
}It is unfortunate that such a (IMHO) basic thing became such a time sink. However, I hope I could help you.
0 Comments