feat: add package to exclude gitignored hooks

tools like renovate can run soonix:update after updating stuff, but the
gitignored hooks cannot be committed anyways, so why bother building
them
This commit is contained in:
technofab 2026-01-01 15:56:25 +01:00
parent 56f281eea4
commit 87399d28fe
Signed by: technofab
SSH key fingerprint: SHA256:bV4h88OqS/AxjbPn66uUdvK9JsgIW4tv3vwJQ8tpMqQ
2 changed files with 116 additions and 78 deletions

View file

@ -153,83 +153,93 @@ in {
config = let
hooks = config.hooks;
hookNames = builtins.attrNames hooks;
# allow excluding gitignore since stuff like renovate can't use/commit it anyways
getHookNames = {includeGitignored ? true}:
if includeGitignored
then (builtins.attrNames hooks)
else
map
(hook: hook.name)
(builtins.filter (hook: !hook.hook.gitignore) (builtins.attrValues hooks));
runHooks = concatMapStringsSep "\n" (hookName: let
hook = hooks.${hookName};
modes = {
link =
# sh
''
if [[ ! -L "${hook.output}" ]] || [[ "$(readlink "${hook.output}")" != "${hook.generatedDerivation}" ]]; then
_soonix_log "info" "${hookName}" "Creating symlink: ${hook.output} -> ${hook.generatedDerivation}"
mkdir -p "$(dirname "${hook.output}")"
ln -sf "${hook.generatedDerivation}" "${hook.output}"
_changed=true
else
_soonix_log "info" "${hookName}" "Symlink up to date: ${hook.output}"
fi
'';
copy =
# sh
''
if [[ ! -f "${hook.output}" ]] || ! cmp -s "${hook.generatedDerivation}" "${hook.output}"; then
_soonix_log "info" "${hookName}" "Copying file: ${hook.generatedDerivation} -> ${hook.output}"
mkdir -p "$(dirname "${hook.output}")"
# required since they're read only
rm -f "${hook.output}"
cp "${hook.generatedDerivation}" "${hook.output}"
_changed=true
else
_soonix_log "info" "${hookName}" "File up to date: ${hook.output}"
fi
'';
};
runHooks = args:
concatMapStringsSep "\n" (hookName: let
hook = hooks.${hookName};
modes = {
link =
# sh
''
if [[ ! -L "${hook.output}" ]] || [[ "$(readlink "${hook.output}")" != "${hook.generatedDerivation}" ]]; then
_soonix_log "info" "${hookName}" "Creating symlink: ${hook.output} -> ${hook.generatedDerivation}"
mkdir -p "$(dirname "${hook.output}")"
ln -sf "${hook.generatedDerivation}" "${hook.output}"
_changed=true
else
_soonix_log "info" "${hookName}" "Symlink up to date: ${hook.output}"
fi
'';
copy =
# sh
''
if [[ ! -f "${hook.output}" ]] || ! cmp -s "${hook.generatedDerivation}" "${hook.output}"; then
_soonix_log "info" "${hookName}" "Copying file: ${hook.generatedDerivation} -> ${hook.output}"
mkdir -p "$(dirname "${hook.output}")"
# required since they're read only
rm -f "${hook.output}"
cp "${hook.generatedDerivation}" "${hook.output}"
_changed=true
else
_soonix_log "info" "${hookName}" "File up to date: ${hook.output}"
fi
'';
};
optionalGitignore =
if hook.hook.gitignore
then ''
_soonix_add_to_gitignore "${hook.output}"
optionalGitignore =
if hook.hook.gitignore
then ''
_soonix_add_to_gitignore "${hook.output}"
''
else "";
in
builtins.addErrorContext "[soonix] while generating script for ${hookName}"
# sh
''
else "";
in
# sh
''
# Process hook: ${hookName}
while IFS= read -r line; do
case "$line" in
UPDATED) _soonix_updated+=("${hookName}") ;;
UPTODATE) _soonix_uptodate+=("${hookName}") ;;
*) echo "$line" ;;
esac
done < <(
set -euo pipefail
_changed=false
# Process hook: ${hookName}
while IFS= read -r line; do
case "$line" in
UPDATED) _soonix_updated+=("${hookName}") ;;
UPTODATE) _soonix_uptodate+=("${hookName}") ;;
*) echo "$line" ;;
esac
done < <(
set -euo pipefail
_changed=false
${modes.${hook.hook.mode} or (throw "Mode ${hook.hook.mode} doesnt exist")}
${modes.${hook.hook.mode} or (throw "Mode ${hook.hook.mode} doesnt exist")}
# Add to gitignore if requested
${optionalGitignore}
# Add to gitignore if requested
${optionalGitignore}
# Run extra commands if file changed
if [[ "$_changed" == "true" && -n "${hook.hook.extra}" ]]; then
_soonix_log "info" "${hookName}" "Running extra command: ${hook.hook.extra}"
eval "${hook.hook.extra}"
fi
# Run extra commands if file changed
if [[ "$_changed" == "true" && -n "${hook.hook.extra}" ]]; then
_soonix_log "info" "${hookName}" "Running extra command: ${hook.hook.extra}"
eval "${hook.hook.extra}"
fi
if [[ "$_changed" == "true" ]]; then
echo "UPDATED"
else
echo "UPTODATE"
fi
) || {
_soonix_log "error" "${hookName}" "Failed to process hook"
_soonix_failed+=("${hookName}")
}
'')
hookNames;
if [[ "$_changed" == "true" ]]; then
echo "UPDATED"
else
echo "UPTODATE"
fi
) || {
_soonix_log "error" "${hookName}" "Failed to process hook"
_soonix_failed+=("${hookName}")
}
'')
(getHookNames args);
generatedShellHook =
generateShellHook = args:
builtins.addErrorContext "[soonix] while generating shell hook"
# sh
''
_soonix_log() {
@ -265,7 +275,7 @@ in {
_soonix_failed=()
_soonix_uptodate=()
${runHooks}
${runHooks args}
local output=$'\E[msoonix:\E[38;5;8m'
local status=0
@ -297,8 +307,8 @@ in {
in rec {
# nothing to do if no hooks exist
shellHook =
if (builtins.length hookNames > 0)
then generatedShellHook
if (builtins.length (builtins.attrNames config.hooks) > 0)
then generateShellHook {}
else "";
shellHookFile = pkgs.writeShellScript "shellHook" shellHook;
devshellModule = {
@ -307,11 +317,17 @@ in {
};
finalFiles = buildAllFiles allFiles;
# make it simpler to update the hooks without any devshell
packages."soonix:update" = pkgs.writeShellScriptBin "soonix:update" ''
function _soonix() {
${shellHook}
}
_soonix
'';
packages = let
mkPackage = args:
pkgs.writeShellScriptBin "soonix:update" ''
function _soonix() {
${generateShellHook args}
}
_soonix
'';
in {
"soonix:update" = mkPackage {};
"soonix:update:excludegitignore" = mkPackage {includeGitignored = false;};
};
};
}